﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using BrainTechLLC;
using System.Windows.Threading;
using System.Windows;
using BrainTechLLC.ThreadSafeObjects;
using System.Threading;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;

namespace BrainTechLLC
{
    public partial class BaseNotifyPropertyChanged : INotifyPropertyChanged
    {
        [NonSerialized]
        public static readonly ThreadSafeLookupNonRef<int, int> SuspendPropertyChangedEvent = new ThreadSafeLookupNonRef<int, int>();

        [NonSerialized]
        public static readonly ThreadSafeLookup<int, ClassAndPropertyChangeCollection> PropertyChangesThatOccurred = new ThreadSafeLookup<int, ClassAndPropertyChangeCollection>();

        [NonSerialized]
        public static Dispatcher _dispatcher;

        [NonSerialized]
        public static bool _gotDispatcher;

        [NonSerialized]
        public static object _lock = new object();
        
        public virtual void AddPropertyChanged(BaseNotifyPropertyChanged classObject, string propertyName)
        {
            var collection = GetPropertyChanges();
            ClassAndPropertyChange p = new ClassAndPropertyChange(classObject, propertyName);
            collection.AddPropertyChange(p);
        }

        public static ClassAndPropertyChangeCollection TryGetPropertyChanges()
        {
            int key = Thread.CurrentThread.ManagedThreadId;
            ClassAndPropertyChangeCollection result;

            if (!PropertyChangesThatOccurred.TryGetValue(key, out result))
            {
                return null;
            }

            return result;
        }

        public static ClassAndPropertyChangeCollection GetPropertyChanges()
        {
            int key = Thread.CurrentThread.ManagedThreadId;
            ClassAndPropertyChangeCollection result;

            if (!PropertyChangesThatOccurred.TryGetValue(key, out result))
            {
                result = new ClassAndPropertyChangeCollection();
                PropertyChangesThatOccurred.Add(key, result);
            }

            return result;
        }

        public static bool SetSuspendPropertyChanged(bool on, bool runAllIfReEnable)
        {
            if (SetSuspendPropertyChanged(on))
            {
                if (runAllIfReEnable)
                {
                    var changes = TryGetPropertyChanges();

                    if (changes != null)
                    {
                        changes.RunAllPropertyChanges();
                    }
                }

                return true;
            }

            return false;
        }

        public static bool SetSuspendPropertyChanged(bool on)
        {
            int key = Thread.CurrentThread.ManagedThreadId;

            if (on)
            {
                int n = SuspendPropertyChangedEvent[key];

                if (n == 0)
                {
                    ClassAndPropertyChangeCollection changes = TryGetPropertyChanges();

                    if (changes != null)
                    {
                        changes.PropertyChanges.Clear();
                    }
                }

                SuspendPropertyChangedEvent[key] = n + 1;
                return false;
            }
            else
            {
                int n = SuspendPropertyChangedEvent[key];

                if (n == 1)
                {
                    SuspendPropertyChangedEvent.Remove(key);
                    return true;
                }
                else
                {
                    SuspendPropertyChangedEvent[key] = n - 1;
                    return false;
                }
            }
        }

        public static int GetSuspendPropertyChanged()
        {
            int result;
            int key = Thread.CurrentThread.ManagedThreadId;

            if (!SuspendPropertyChangedEvent.TryGetValue(key, out result))
            {
                result = 0;
            }

            return result;
        }
    } 
}
